/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.diagram.composite.command;

import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.commands.Command;
import org.eclipse.uml2.uml.Interface;

import com.cea.papyrus.core.helper.GraphEdgeHelper;
import com.cea.papyrus.core.helper.NodeHelper;
import com.cea.papyrus.diagram.composite.helper.NodeInterfaceHelper;
import com.cea.papyrus.diagraminterchange2.di2.Di2Factory;
import com.cea.papyrus.diagraminterchange2.di2.DiagramElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphConnector;
import com.cea.papyrus.diagraminterchange2.di2.GraphEdge;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;

/**
 * This command is used to add a representation of a provided or required Interface into the ddiagram
 */
public class InterfaceDisplayCommand extends Command {

	/** distance to which the end of the interface is created */ 
	protected final static int DISTANCE=100;
	
	/** name of the interface created */
	protected String name;

	/**
	 * maybe this is the nameLable of the port od the graphnode that represents the port.
	 */
	protected DiagramElement elementSource;

	/**
	 * 
	 */
	protected NodeHelper factory;

	/**
	 * 
	 */
	protected GraphNode interfaceNode;
	protected Interface anInterface;

	/**
	 * 
	 */
	protected DiagramElement parent;

	/**
	 * Creates a new InterfaceDisplayCommand
	 * @param name the name of the command
	 * @param elementSource the source diagram element
	 * @param anInterface the interface to display
	 * @param parent the parent diagram element
	 */
	public InterfaceDisplayCommand(String name, DiagramElement elementSource,Interface anInterface, DiagramElement parent) {
		factory = new NodeInterfaceHelper();
		setLabel("Display Interface "+name);
		this.name = name;
		this.elementSource = elementSource;
		this.parent = parent;
		this.anInterface=anInterface;
	}

	/**
	 * Creates a new InterfaceDisplayCommand
	 * @param elementSource the source diagram element
	 * @param anInterface the interface to display
	 * @param parent the parent diagram element
	 */
	public InterfaceDisplayCommand(DiagramElement elementSource,Interface anInterface, DiagramElement parent) {
		this(anInterface.getName(), elementSource, anInterface, parent);
	}

	/* (non-Javadoc)
	 * @see org.eclipse.gef.commands.Command#execute()
	 */
	/**
	 * 
	 */
	@Override
	public void execute() {
		if(canExecute()){

			//1.Calculate inside rectangle of the part that contains the port.
			Rectangle insideRect= new Rectangle(((GraphNode)(elementSource.getSemanticParent())).getPosition().getCopy(),
					((GraphNode)(elementSource.getSemanticParent())).getSize().getCopy());
			insideRect.crop(new Insets(1));
			//2. Calulate bounds of the port
			Rectangle portBound=new Rectangle(((GraphNode)elementSource).getPosition().getCopy(),
					((GraphNode)elementSource).getSize().getCopy());
			//3. Dectection of the orientation of the portNode

			int portOrientation=insideRect.getPosition(portBound.getCenter());

			//4. we have to place the port by taking account port orientation.
			Point interfacePosition; //position of the interface
			Point sourcePos=null; // position of the source anchor of the link
			Point targetPos=null;// position of the target anchor of the link
			GraphEdge edge=null ;// link between the interface and the port
			GraphEdgeHelper ge= new GraphEdgeHelper();
			
			switch (portOrientation){
			case PositionConstants.EAST:
				//calculus of the position of the interface.
				interfacePosition= new Point(((GraphElement)elementSource).getPosition().x+DISTANCE, 
						((GraphElement)elementSource).getPosition().y);
				//creation of the interface
				interfaceNode=factory.createGraphElement(anInterface,(GraphElement)elementSource,interfacePosition,new Dimension(40,40));
				//creation of the graphEdge
			
				edge = (GraphEdge)ge.createGraphElement(null, (GraphElement)parent, null, null);

				sourcePos = new Point(interfaceNode.getPosition().x, 
						interfaceNode.getPosition().y+interfaceNode.getSize().height/2);
				targetPos = new Point(((GraphElement)elementSource).getPosition().x+((GraphNode)elementSource).getSize().width, 
						((GraphElement)elementSource).getPosition().y+((GraphNode)elementSource).getSize().height/2);
				break;
			case PositionConstants.WEST:
//				calculus of the position of the interface.
				interfacePosition= new Point(((GraphElement)elementSource).getPosition().x-DISTANCE, 
						((GraphElement)elementSource).getPosition().y);
				//creation of the interface
				interfaceNode=factory.createGraphElement(anInterface,(GraphElement)elementSource,interfacePosition,new Dimension(40,40));
				//creation of the graphEdge
				edge = (GraphEdge)ge.createGraphElement(null, (GraphElement)parent, null, null);

				sourcePos = new Point(interfaceNode.getPosition().x+interfaceNode.getSize().width, 
						interfaceNode.getPosition().y+interfaceNode.getSize().height/2);
				targetPos = new Point(((GraphElement)elementSource).getPosition().x, 
						((GraphElement)elementSource).getPosition().y+((GraphNode)elementSource).getSize().height/2);
				break;
			case PositionConstants.NORTH:
				//calculus of the position of the interface.
				interfacePosition= new Point(((GraphElement)elementSource).getPosition().x, 
						((GraphElement)elementSource).getPosition().y-DISTANCE);
				//creation of the interface
				interfaceNode=factory.createGraphElement(anInterface,(GraphElement)elementSource,interfacePosition,new Dimension(40,40));
				//creation of the graphEdge
				edge = (GraphEdge)ge.createGraphElement(null, (GraphElement)parent, null, null);

				sourcePos = new Point(interfaceNode.getPosition().x+interfaceNode.getSize().width/2, 
						interfaceNode.getPosition().y+interfaceNode.getSize().height);
				targetPos = new Point(((GraphElement)elementSource).getPosition().x+((GraphNode)elementSource).getSize().width/2, 
						((GraphElement)elementSource).getPosition().y);
				break;
				
			case PositionConstants.SOUTH:
//				calculus of the position of the interface.
				interfacePosition= new Point(((GraphElement)elementSource).getPosition().x, 
						((GraphElement)elementSource).getPosition().y+DISTANCE);
				//creation of the interface
				interfaceNode=factory.createGraphElement(anInterface,(GraphElement)elementSource,interfacePosition,new Dimension(40,40));
				//creation of the graphEdge
				edge = (GraphEdge)ge.createGraphElement(null, (GraphElement)parent, null, null);

				sourcePos = new Point(interfaceNode.getPosition().x+interfaceNode.getSize().width/2, 
						interfaceNode.getPosition().y);
				targetPos = new Point(((GraphElement)elementSource).getPosition().x+((GraphNode)elementSource).getSize().width/2, 
						((GraphElement)elementSource).getPosition().y+((GraphNode)elementSource).getSize().height);
				break;
			}
			// create source anchor/connector
			GraphConnector srcConnector = Di2Factory.eINSTANCE.createGraphConnector();
			srcConnector.setPosition(targetPos);
			// create target connector
			GraphConnector targetConnector = Di2Factory.eINSTANCE.createGraphConnector();
			targetConnector.setPosition(sourcePos);
			// connect to graphEdge [0]=source  [1]=target
			edge.getAnchor().add(srcConnector);
			edge.getAnchor().add(targetConnector);
			edge.setSemanticParent(interfaceNode);

			getSourceAnchor(edge).setGraphElement((GraphElement)elementSource);
			getTargetAnchor(edge).setGraphElement(interfaceNode);
			edge.setContainer((GraphElement)parent);


		}

	}



	/**
	 * Computes the middle point between p1 and p2.
	 * 
	 * @param p1 
	 * @param p2 
	 * 
	 * @return 
	 */
	protected Point middlePoint(Point p1, Point p2){
		Dimension d = p2.getDifference(p1);
		return new Point(p1.x + d.width / 2, p1.y + d.height / 2);
	}

	/**
	 * 
	 * 
	 * @param edge 
	 * 
	 * @return The target anchor of the specified edge.
	 */
	protected GraphConnector getTargetAnchor(GraphEdge edge) {
		return ((GraphConnector)edge.getAnchor().get(1));
	}

	/**
	 * 
	 * 
	 * @param edge 
	 * 
	 * @return The source anchor of the specified edge.
	 */
	protected GraphConnector getSourceAnchor(GraphEdge edge) {
		return ((GraphConnector)edge.getAnchor().get(0));
	}


	/* (non-Javadoc)
	 * @see org.eclipse.gef.commands.Command#redo()
	 */
	/**
	 * 
	 */
	@Override
	public void redo() {
		execute();
	}

	/* (non-Javadoc)
	 * @see org.eclipse.gef.commands.Command#undo()
	 */
	/**
	 * 
	 */
	@Override
	public void undo() {

	}

	/**
	 * This method tests if the graphNode is allowed to be created.
	 * 
	 * @return 
	 */
	@Override
	public boolean canExecute() {

		return true;	

	}

}